#ifndef CANGJIE_H
#define CANGJIE_H

#ifdef __cplusplus
#include <cstddef>
#include <cstdint>
#include <functional>
#ifndef _WIN64
#include <csignal>
#endif
#else
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#ifndef _WIN64
#include <signal.h>
#endif
#endif

#ifdef __cplusplus
#define CANGJIE_RT_API_DECLS_BEGIN extern "C" {
#define CANGJIE_RT_API_DECLS_END }
#else
#define CANGJIE_RT_API_DECLS_BEGIN
#define CANGJIE_RT_API_DECLS_END
#endif

#ifndef MRT_EXPORT
#define MRT_EXPORT __attribute__((visibility("default")))
#endif

#ifndef MRT_OPTIONAL_DISABLE_TAIL_CALL
#ifdef __OHOS__
#define MRT_OPTIONAL_DISABLE_TAIL_CALL __attribute__((disable_tail_calls))
#else
#define MRT_OPTIONAL_DISABLE_TAIL_CALL
#endif
#endif

#ifndef MRT_OPTIONAL_BRANCH_PROTECT_NONE
#if (defined(__OHOS__) && defined(__aarch64__)) || defined(__HOS__)
#define MRT_OPTIONAL_BRANCH_PROTECT_NONE __attribute__((target("branch-protection=none")))
#else
#define MRT_OPTIONAL_BRANCH_PROTECT_NONE
#endif
#endif

#ifdef __cplusplus

using CJThreadHandle = void*;

using SemiCJThreadHandle = void*;

using CJTaskFunc = void* (*)(void*);

using CJThreadKey = unsigned int;

using DestructorFunc = void (*)(void*);

using PostTaskFunc = bool (*)(void*);

using HasHigherPriorityTaskFunc = bool (*)();
#else

typedef void* CJThreadHandle;

typedef void* SemiCJThreadHandle;

typedef void* (*CJTaskFunc)(void*);

typedef unsigned int CJThreadKey;

typedef void (*DestructorFunc)(void*);

typedef bool (*PostTaskFunc)(void*);

typedef bool (*HasHigherPriorityTaskFunc)(void);
#endif

struct CJThreadSpecificData {
    CJThreadKey key;
    void* value;
};

#ifdef __cplusplus
struct CJErrorObject {
    const char* name;
    const char* message;
    const char* stack;
};

struct CJUncaughtExceptionInfo {
    const char* hapPath;
    std::function<void(const char* summary, const CJErrorObject errorObj)> uncaughtTask;
};
#endif

enum CJThreadState {
    CJTHREAD_IDLE,
    CJTHREAD_READY,
    CJTHREAD_RUNNING,
    CJTHREAD_PENDING,
    CJTHREAD_SYSCALL,
};

enum SemiCJThreadState {
    SEMI_CJTHREAD_INIT,
    SEMI_CJTHREAD_SUSPENDING,
    SEMI_CJTHREAD_RUNNING,
    SEMI_CJTHREAD_DONE,
};

enum RTLogLevel {
    RTLOG_VERBOSE,
    RTLOG_DEBUGY,
    RTLOG_INFO,
    RTLOG_WARNING,
    RTLOG_ERROR,
    RTLOG_FATAL_WITHOUT_ABORT,
    RTLOG_FATAL,
    RTLOG_OFF
};

enum RTErrorCode { E_OK = 0, E_ARGS = -1, E_TIMEOUT = -2, E_STATE = -3, E_FAILED = -4 };

struct HeapParam {
    size_t regionSize;
    size_t heapSize;
    double exemptionThreshold;
    double heapUtilization;
    double heapGrowth;
    double allocationRate;
    size_t allocationWaitTime;
};

struct GCParam {
    size_t gcThreshold;
    double garbageThreshold;
    uint64_t gcInterval;
    uint64_t backupGCInterval;
    int32_t gcThreads;
};

struct LogParam {
    enum RTLogLevel logLevel;
};

struct ConcurrencyParam {
    size_t thStackSize;
    size_t coStackSize;
    uint32_t processorNum;
};

struct RuntimeParam {
    struct HeapParam heapParam;
    struct GCParam gcParam;
    struct LogParam logParam;
    struct ConcurrencyParam coParam;
};

CANGJIE_RT_API_DECLS_BEGIN

MRT_EXPORT enum RTErrorCode InitCJRuntime(const struct RuntimeParam* param);

MRT_EXPORT void* InitUIScheduler(void);
MRT_EXPORT enum RTErrorCode RunUIScheduler(unsigned long long timeout);
MRT_EXPORT enum RTErrorCode SetCJCommandLineArgs(int argc, const char* argv[]);
MRT_EXPORT enum RTErrorCode FiniCJRuntime(void);
MRT_EXPORT enum RTErrorCode SetRuntimeInitFlag(void);

MRT_EXPORT enum RTErrorCode SetRuntimeFiniFlag(void);

MRT_EXPORT CJThreadHandle RunCJTask(const CJTaskFunc func, void* args);
MRT_EXPORT CJThreadHandle RunCJTaskSignal(const CJTaskFunc func, void* args);
MRT_EXPORT CJThreadHandle RunCJTaskToSchedule(const CJTaskFunc func, void* args, void* schedule);

MRT_EXPORT CJThreadHandle RunCJTaskWithLocal(
    const CJTaskFunc func, void* args, struct CJThreadSpecificData* data, int num);

MRT_EXPORT SemiCJThreadHandle CreateCJThread(
    const CJTaskFunc func, void* arg, struct CJThreadSpecificData* data, int num);

MRT_EXPORT int SuspendCJThread(void);

MRT_EXPORT int ResumeCJThread(SemiCJThreadHandle co);

MRT_EXPORT int GetCJThreadState(SemiCJThreadHandle co);

MRT_EXPORT void* GetCJThreadResult(SemiCJThreadHandle co);

MRT_EXPORT int DestoryCJThread(SemiCJThreadHandle co);

MRT_EXPORT int SuspendSchedule(void);

MRT_EXPORT int ResumeSchedule(void);

MRT_EXPORT bool AnyTask(void);

typedef unsigned int (*NetPollNotifyFunc)(int fd, int event, void* arg);

#if defined(__linux__) || defined(hongmeng) || defined(__APPLE__)

MRT_EXPORT void* NetPollNotifyAdd(int fd, int events, NetPollNotifyFunc func, void* arg);

MRT_EXPORT int NetPollNotifyDel(int fd, void* pd);
#endif

MRT_EXPORT int GetTaskRet(const CJThreadHandle handle, void** ret);

MRT_EXPORT int GetTaskRetWithTimeout(const CJThreadHandle handle, void** ret, int64_t timeout);

MRT_EXPORT void ReleaseHandle(const CJThreadHandle handle);

MRT_EXPORT int CJThreadKeyCreate(CJThreadKey* key, DestructorFunc destructor);

MRT_EXPORT int CJThreadSetspecific(CJThreadKey key, void* value);

MRT_EXPORT void* CJThreadGetspecific(CJThreadKey key);

MRT_EXPORT void RegisterEventHandlerCallbacks(PostTaskFunc pFunc, HasHigherPriorityTaskFunc hFunc);

MRT_EXPORT int LoadCJLibrary(const char* libName);

MRT_EXPORT int InitCJLibrary(const char* libName);

MRT_EXPORT int LoadCJLibraryWithInit(const char* libName);

MRT_EXPORT void* FindCJSymbol(const char* libName, const char* symbolName);

MRT_EXPORT int UnloadCJLibrary(const char* libName);

#ifndef _WIN64

struct SignalAction {
    union {
        void (*saHandler)(int);
        bool (*saSignalAction)(int, siginfo_t*, void*);
    };
    sigset_t scMask;
    uint64_t scFlags;
};

MRT_EXPORT void AddHandlerToSignalStack(int signal, struct SignalAction* sa);

MRT_EXPORT void RemoveHandlerFromSignalStack(int signal, bool (*fn)(int, siginfo_t*, void*));
#endif

#ifdef __cplusplus
MRT_EXPORT void RegisterUncaughtExceptionHandler(const CJUncaughtExceptionInfo& handle);
#endif

CANGJIE_RT_API_DECLS_END

#endif // CANGJIE_H